package org.nanhill.commons.pattern;

import java.util.ArrayList;
import java.util.List;

/**
 * 
 * @author alin
 * 
 */
public class DefaultObservable implements Observable {
	private boolean changed = false;

	private List<Observer> obs;

	private final byte[] lock = new byte[0];

	public DefaultObservable() {
		obs = new ArrayList<Observer>();
	}

	public void addObserver(Observer o) {
		if (o == null)
			return;
		synchronized (lock) {
			if (!obs.contains(o)) {
				obs.add(o);
			}
		}
	}

	public void deleteObserver(Observer o) {
		synchronized (lock) {
			obs.remove(o);
		}
	}

	public void notifyObservers(Object arg) {
		Object[] arrLocal;
		synchronized (lock) {
			/*
			 * We don't want the Observer doing callbacks into arbitrary code
			 * while holding its own Monitor. The code where we extract each
			 * Observable from the List and store the state of the Observer
			 * needs synchronization, but notifying observers does not (should
			 * not). The worst result of any potential race-condition here is
			 * that: 1) a newly-added Observer will miss a notification in
			 * progress 2) a recently unregistered Observer will be wrongly
			 * notified when it doesn't care
			 */
			if (!changed)
				return;
			arrLocal = obs.toArray();
			clearChanged();
		}
		for (int i = arrLocal.length - 1; i >= 0; i--)
			((Observer) arrLocal[i]).update(this, arg);
	}

	/**
	 * 
	 */
	protected void setChanged() {
		synchronized (lock) {
			changed = true;
		}
	}

	protected void clearChanged() {
		synchronized (lock) {
			changed = false;
		}
	}

}
